package 
{
	import control.macro.HumanWorldController;
	import control.micro.AttackingAIBattleController;
	import control.micro.AttackingHumanBattleController;
	import control.micro.BattleController;
	import control.micro.DefendingAIBattleController;
	import control.micro.DefendingHumanBattleController;
	import events.BattleEvent;
	import events.WorldEvent;
	import flash.display.Sprite;
	import flash.events.Event;
	import model.BattleReport;
	import model.macro.Unit;
	import model.macro.World;
	import model.micro.Battle;
	import view.macro.MapSprite;
	import view.macrogui.MacroHUD;
	import view.micro.BattleSprite;
	import view.microgui.HUDSprite;
	
	/**
	 * ...
	 * @author John
	 */
	public class Game extends Sprite
	{
		private var human_world_controller:HumanWorldController;
		private var _world:World;
		private var _map:MapSprite;
		private var _previous_battles:Vector.<BattleReport>;
		private var hud:MacroHUD;
		
		public function Game(world:World, map_sprite:MapSprite, previous_battles:Vector.<BattleReport>)
		{
			_map = map_sprite;
			_world = world;
			_previous_battles = previous_battles
			addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		public function init(e:Event):void
		{	
			_map = new MapSprite(_world.territories, _world);
			addChild(_map);
			
			hud = new MacroHUD(_world, _map);
			addChild(hud);
			
			human_world_controller = new HumanWorldController(_world.players[0], _world, stage);
			
			_world.addEventListener(WorldEvent.BATTLE_BEGIN, startBattle);
		}
		
		// model should auto update
		public function startBattle(e:WorldEvent):void
		{
			toggleMacro();
			var battle:Battle = new Battle((e.data['attackingUnits'] as Vector.<Unit>).concat(), e.data['defendingTerritory'].units, e.data['defendingTerritory'].fortress, e.data['defendingTerritory'], e.data['attackingTerritory']);
			
			// views
			var battle_sprite:BattleSprite = new BattleSprite(battle);
			addChild(battle_sprite);
			
			var microHUD:HUDSprite = new HUDSprite(battle);
			addChild(microHUD);
			battle_sprite.y = stage.stageHeight;
			
			// controllers
			var defending_controller:BattleController;
			var attacking_controller:BattleController;
			
			if (human_world_controller.player == battle.invading_territoy.owner) // Defending human
			{
				defending_controller = new DefendingAIBattleController(battle);
				attacking_controller = new AttackingHumanBattleController(battle, stage);
			}
			else if (human_world_controller.player == battle.defending_territory.owner) // Attacking human
			{
				defending_controller = new DefendingHumanBattleController(battle, stage);
				attacking_controller = new AttackingAIBattleController(battle);
			}
			else if (1 == 2) // Both human (Okay, this shouldn't exist)
			{
				defending_controller = new DefendingHumanBattleController(battle, stage);
				attacking_controller = new AttackingHumanBattleController(battle, stage);
			}
			else // Both AI (simulation)
			{
				defending_controller = new DefendingAIBattleController(battle);
				attacking_controller = new AttackingAIBattleController(battle);
			}
			
			addEventListener(Event.ENTER_FRAME, update);
			battle.addEventListener(BattleEvent.BATTLE_ENDED, battleEnded);
			
			/**
			 * Called every frame.
			 * @param	e	EnterFrame event
			 */
			function update(e:Event):void
			{
				if (battle != null)
				{
					battle.update();
					battle_sprite.update();
					hud.update();
					defending_controller.update();
					attacking_controller.update();
				}
				else
				{
					toggleMacro();
					removeEventListener(Event.ENTER_FRAME, update);
					removeChild(battle_sprite);
					removeChild(microHUD);
				}
			}
			
			function battleEnded(e:BattleEvent):void
			{ 
				_previous_battles.push(e.data as BattleReport);
				processLastBattle();
				battle = null;
			}
		}
		
		public function processLastBattle():void
		{
			var report:BattleReport = _previous_battles[_previous_battles.length - 1];
			
			if (report.win_condition == BattleReport.RETREAT_BY_ATTACKER)
			{
				// Do something...
			}
			else if (report.win_condition == BattleReport.RETREAT_BY_DEFENDER)
			{
				_world.territories[_world.territories.indexOf(report.battle_territory)].owner = report.winner;
				_world.transferUnits(report.invading_territory, report.remainingUnits, report.battle_territory);
			}
		}
		
		public function toggleMacro():void
		{
			_map.visible = !_map.visible;
			hud.visible = !hud.visible;
		}
		
		public function get world():World
		{
			return _world;
		}
		
		public function get map():MapSprite 
		{
			return _map;
		}
	
	}
}